/**
 * Created by zengxm on 12/21/2016.
 */
const waterfall=require('async').waterfall
const sshConnect=require('../service.ssh').connect
const U=require("../../core/Utils")
const logger = U.logger("JDK")
const fs=require('fs')
const path = require('path')
const ProgressBar=require('progress')

const MIN_JDK="1.8"
const JDK_HOME = "/var/camphor/jdk"
const JDK_ZIP = path.join(__dirname,"jdk1.8.tar.gz")


/*
读取package文件
 */
var _package = U.readToJSON(__dirname+"/package.json")    //来自package的数据
if(!_package.config)    _package.config = {}
const localFile = _package.config.jdkPath?_package.config.jdkPath:JDK_ZIP
const localFilename = path.basename(localFile)          //本地文件名

/**
 * 检测JDK的版本，这里需要最低1.8+
 * @param ssh
 * @param cb
 * @private
 */
function _checkVersion(ssh,cb) {
    ssh.execCommand('source /etc/environment && source /etc/profile && java -version').then(function(result) {
        if(result.code==0){
            const jdkVersion=result.stderr
            //检测JDK版本
            const exec=/"([^"]*)"/.exec(jdkVersion)||[]
            if(exec!=null && exec[1]>=MIN_JDK){
                cb(new Error("java 已经安装(min version "+MIN_JDK+")，版本信息：\n"+ result.stderr))
            }else
                cb(new Error("检测到低版本或无效的JDK,version = "+ exec[1]))
        }else{
            logger.info(("未检测到JDK : "+result.stderr).magenta)
            cb()
        }
    })
}

/**
 * 上传JDK到远程目录，流程如下：
 *  1.开启sftp通道（使用SSH2）
 *  2.计算远程文件的完整路径： JDK_HOME + 本地文件名
 *  3.判断远程文件是否存在
 *  4.若存在：则判断是否需要覆盖，如果不覆盖则结束流程
 *  5.若不存在：则尝试创建远程目录
 *  6.执行上传
 *
 * @param ssh
 * @param cb
 * @param replace
 * @private
 */
function _uploadJDK(ssh, cb, replace) {
    //判断本地文件是否存在
    if(!fs.existsSync(localFile)) return cb(new Error(localFile+" 不存在，无法上传 （请到http://www.oracle.com/technetwork/java/javase/downloads/index.html下载最新的JDK压缩包）"))
    const localStat = fs.statSync(localFile)

    const remote = JDK_HOME+"/"+path.basename(localFile)
    logger.log("准备上传JDK压缩包 "+localFile+" 到 "+remote)
    ssh.connection.sftp((err,sftp)=>{
        if(err) cb(new Error("无法创建SFTP ： "+err.message))

        //执行上传
        function _upload() {
            logger.info("开始上传...")
            //读取本地文件大小

            const bar = new ProgressBar('upload :bar :rate/bps :percent :etas (use :elapsed s)', {
                complete:'\033[42m \033[0m',
                // incomplete:'\u001b[41m \u001b[0m',
                width: 100,
                total: localStat.size
            });

            //开始上传
            sftp.fastPut(
                localFile,
                remote,{
                    //上传进度监听
                    step:function(send,chunk,total){
                        // logger.info("上传---%d / %d",send,total)
                        bar.update(send/total)
                    }
                },
                (putErr)=>{
                    if(putErr) return cb(new Error("上传失败 ： "+putErr.message))

                    logger.info("JDK压缩包上传成功！")
                    cb(null,remote)
                }
            );
        }

        //查看文件是否存在
        sftp.stat(remote,(ftErr,stat)=>{
            //如果文件不存在，则尝试创建文件夹
            if(ftErr){
                const remoteDir=path.dirname(remote)

                ssh.mkdir(remoteDir, 'exec').then(function(){
                    logger.info("远程目录 "+remoteDir+" 创建成功")
                    _upload()
                },function (err) {
                    cb(new Error("无法创建远程目录："+err.message))
                })
            }
            //如果文件存在
            else{
                //判断是否覆盖
                if(!replace) {
                    logger.info(remote.magenta+" 已经存在，replace=false，进程即将中断...")
                    return cb(null,remote)
                }

                logger.info("远程文件 "+remote+" 已存在，准备上传并覆盖原文件")
                _upload()
            }
        })
    })
}

/**
 * 解压JDK压缩包
 * @param ssh
 * @param remotePath        远程JDK的路径
 * @param cb                回调函数
 * @private
 */
function _unzip(ssh,remotePath, cb) {
    logger.info("解压文件："+remotePath)
    ssh.exec("tar",['-xf', localFilename],{cwd:JDK_HOME}).then(result=>{
        ssh.execCommand("ls",{cwd:JDK_HOME})
            .then(result=>{
                var unzipFile=""
                result.stdout.split("\n").forEach(n=>{
                    if(n!==localFilename && n.startsWith("jdk"))
                        unzipFile=n;
                })
                logger.info("解压成功：%s/%s",JDK_HOME,unzipFile)
                cb(null, JDK_HOME+"/"+unzipFile)
            },
                (err)=> cb(new Error("无法解压 "+err.message)))
    },err=>cb(new Error("解压出错 ："+err.message)))
}

function _setJDKEnv(ssh,jdkHome,cb) {
    logger.log("配置JDK:"+jdkHome)
    const echo= 'echo "export JAVA_HOME='+jdkHome+'" >> /etc/profile && ' +
        'echo "export PATH=\\$PATH:\\$JAVA_HOME/bin" >> /etc/profile && ' +
        'source /etc/profile && ' +
        // 'echo "PATH=\"\\$PATH:'+jdkHome+'/bin\"" >> /etc/environment && ' +
        'source /etc/environment'
    ssh.execCommand(echo).then(result=>{
        echo.split("&&").forEach(e=>logger.log("[exec] "+e))
        logger.info("配置写入成功！")

        cb("done")
    })
}

exports.run=(hosts,options)=>{
    hosts.forEach(host=>{
        const ssh=sshConnect(host, ()=>{
            //检测环境
            if(options.check){
                logger.log("即将检测java环境 on "+host.ip+":"+host.port)
                _checkVersion(ssh,err=>{
                    if(err){
                        logger.log("-------%s:%d 的JDK检测结果-------",host.ip,host.port)
                        console.log(err.message.magenta)
                        logger.log("-------%s:%d 的JDK检测结果-------",host.ip,host.port)
                    }
                    ssh.dispose()
                })
            }else{
                waterfall([
                    //检测java 版本
                    (cb)=>_checkVersion(ssh,cb),
                    //上传JDK压缩包
                    (cb)=>_uploadJDK(ssh, cb,options.replace),
                    //解压
                    (remote,cb)=>_unzip(ssh,remote,cb),
                    //配置JAVA环境
                    (jdkHome,cb)=>_setJDKEnv(ssh,jdkHome,cb)
                ],(err,result)=>{
                    if(err) console.log((err.message || "---").red)
                    ssh.dispose()
                })
            }
        })
    })
}